package com.tn.installer;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.xpath.XPathExpressionException;

import org.xml.sax.SAXException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.ProjectHelper;
import org.apache.tools.ant.DefaultLogger;
import org.apache.tools.ant.BuildEvent;

/**
 * Runs the installer.
 */
public class InstallRunner
{
  private static final Logger LOGGER = LoggerFactory.getLogger(InstallRunner.class);

  private static final String ACTION_INSTALL          = "install";
  private static final String ACTION_UNINSTALL        = "uninstall";
  private static final File   DEPLOYMENT_XML          = new File("./deployment.xml");
  private static final int    INDEX_ACTION            = 0;
  private static final int    INDEX_INSTALL_DIRECTORY = 1;
  private static final String INSTALL_SCRIPT_DIR      = "/.install";
  private static final String INSTALL_SCRIPT_XML      = "install.xml";

  /**
   * Program entry point.
   */
  public static void main(String[] args)
  {
    File installScript = new File(args[INDEX_INSTALL_DIRECTORY] + INSTALL_SCRIPT_DIR, INSTALL_SCRIPT_XML);

    if (ACTION_INSTALL.equalsIgnoreCase(args[INDEX_ACTION]))
    {
      doUninstall(installScript);
      doInstall(installScript);
    }
    else if (ACTION_UNINSTALL.equalsIgnoreCase(args[INDEX_ACTION]))
    {
      doUninstall(installScript);
    }
    else
    {
      printSyntax();
    }
  }

  /**
   * Performs an install to the <code>installDirectory</code>.
   */
  private static void doInstall(File installScript)
  {
    try
    {
      if (!installScript.getParentFile().exists())
      {
        installScript.getParentFile().mkdir();
      }

      InstallScriptWriter installScriptWriter = new InstallScriptWriter(
        DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(DEPLOYMENT_XML)
      );
      installScriptWriter.writeInstallScript(installScript);

      executeTarget(installScript, "install");
    }
    catch (SAXException e)
    {
      LOGGER.error("An error occurred parsing deployment.xml.", e);
    }
    catch (ParserConfigurationException e)
    {
      LOGGER.error("An error occurred creating the document builder.", e);
    }
    catch (FileNotFoundException e)
    {
      LOGGER.error("Cannot find the deployment.xml file in current directory.", e);
    }
    catch (IOException e)
    {
      LOGGER.error("An error occurred reading the deployment.xml file.", e);
    }
    catch (XPathExpressionException e)
    {
      LOGGER.error("An error occurred reading the deployment.xml file.", e);
    }
    catch (XMLStreamException e)
    {
        LOGGER.error("An error occurred writing the install script.", e);
    }
  }

  /**
   * Performs an uninstall.
   */
  private static void doUninstall(File installScript)
  {
    if (installScript.exists())
    {
      executeTarget(installScript, "uninstall");
    }
  }

  /**
   * Executes the <code>target</code> in the <code>installScript</code>.
   */
  private static void executeTarget(File installScript, String target)
  {
    Project project = new Project();
    project.setUserProperty("ant.file", installScript.getAbsolutePath());
    project.setBasedir(installScript.getParentFile().getParent());
    project.addBuildListener(
      new DefaultLogger()
      {
        public void messageLogged(BuildEvent buildEvent)
        {
          System.out.println(buildEvent.getMessage());
        }
      }
    );
    project.init();

    ProjectHelper projectHelper = ProjectHelper.getProjectHelper();
    project.addReference("ant.projectHelper", projectHelper);
    projectHelper.parse(project, installScript);

    project.executeTarget(target);
  }

  /**
   * Prints the syntax required to run this class.
   */
  private static void printSyntax()
  {

  }
}
